package com.baidu.iit.pxp.util;

import com.baidu.iit.pvm.ActivityException;
import com.baidu.iit.pvm.ActivityIllegalArgumentException;
import com.baidu.iit.pxp.event.ActivityEvent;
import com.baidu.iit.pxp.event.ActivityEventType;
import com.baidu.iit.pxp.listener.ActivityEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: huangweili
 * Date: 14-4-30
 * Time: 上午10:34
 */
public class ActivityEventSupport {

    private static Logger logger = LoggerFactory.getLogger(ActivityEventSupport.class);

    protected List<ActivityEventListener> eventListeners;
    protected Map<ActivityEventType, List<ActivityEventListener>> typedListeners;

    public ActivityEventSupport() {
        eventListeners = new ArrayList<ActivityEventListener>();
        typedListeners = new HashMap<ActivityEventType, List<ActivityEventListener>>();
    }

    public synchronized void addEventListener(ActivityEventListener listenerToAdd) {
        if (listenerToAdd == null) {
            throw new ActivityIllegalArgumentException("Listener cannot be null.");
        }
        if (!eventListeners.contains(listenerToAdd)) {
            eventListeners.add(listenerToAdd);
        }
    }

    public synchronized void addEventListener(ActivityEventListener listenerToAdd, ActivityEventType... types) {
        if (listenerToAdd == null) {
            throw new ActivityIllegalArgumentException("Listener cannot be null.");
        }

        if (types == null || types.length == 0) {
            addEventListener(listenerToAdd);
        }

        for (ActivityEventType type : types) {
            addTypedEventListener(listenerToAdd, type);
        }
    }

    public void removeEventListener(ActivityEventListener listenerToRemove) {
        eventListeners.remove(listenerToRemove);

        for (List<ActivityEventListener> listeners : typedListeners.values()) {
            listeners.remove(listenerToRemove);
        }
    }

    public void dispatchEvent(ActivityEvent event) {
        if (event == null) {
            throw new ActivityIllegalArgumentException("Event cannot be null.");
        }

        if (event.getType() == null) {
            throw new ActivityIllegalArgumentException("Event type cannot be null.");
        }
        if (eventListeners.size() > 0) {
            for (ActivityEventListener listener : eventListeners) {
                dispatchEvent(event, listener);
            }
        }

        List<ActivityEventListener> typed = typedListeners.get(event.getType());
        if (typed != null && typed.size() > 0) {
            for (ActivityEventListener listener : typed) {
                dispatchEvent(event, listener);
            }
        }
    }

    protected void dispatchEvent(ActivityEvent event, ActivityEventListener listener) {
        try {
            listener.onEvent(event);
        } catch (Throwable t) {
            if (listener.isFailOnException()) {
                throw new ActivityException("Exception while executing event-listener", t);
            } else {
                logger.warn("Exception while executing event-listener, which was ignored", t);
            }
        }
    }

    protected synchronized void addTypedEventListener(ActivityEventListener listener, ActivityEventType type) {
        List<ActivityEventListener> listeners = typedListeners.get(type);
        if (listeners == null) {
            listeners = new ArrayList<ActivityEventListener>();
            typedListeners.put(type, listeners);
        }

        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }
}
